<template>
    <div class="wh-100% flex gap-10px">
        <div class="w-75% h-full flex flex-col gap-10px">
            <n-card>
                <n-popover
                    trigger="click"
                    :show="showPopover"
                    @clickoutside="showPopover = false"
                >
                    <template #trigger>
                        <div class="h-full flex justify-between cursor-pointer">
                            <DynamicParam :search-params="searchParams" />
                            <n-button-group>
                                <n-button
                                    :focusable="false"
                                    @click="showPopover = true"
                                >
                                    <template #icon>
                                        <n-icon :component="List" />
                                    </template>
                                    筛选
                                </n-button>
                                <n-button
                                    :focusable="false"
                                    @click="handleRefresh"
                                >
                                    <template #icon>
                                        <n-icon :component="ReloadCircle" />
                                    </template>
                                    刷新
                                </n-button>
                            </n-button-group>
                        </div>
                    </template>
                    <RoomSearch
                        :search-params="searchParams"
                        @filter-params="handleSearchRooms"
                    />
                </n-popover>
            </n-card>
            <div v-if="meetingRooms.length === 0" class="wh-100% flex-center">
                <n-result
                    status="404"
                    title="暂无会议室"
                    description="真是寂寞如雪啊"
                />
            </div>
            <n-infinite-scroll v-else :distance="40" @load="loadMeetingRooms">
                <n-grid
                    cols="m:2 l:3 xl:4"
                    responsive="screen"
                    :x-gap="20"
                    :y-gap="20"
                >
                    <n-gi
                        v-for="(item, index) in meetingRooms"
                        :key="index"
                        @click="handleClickRoomItem(item)"
                        @contextmenu="(e: MouseEvent) => handleContextMenu(e, item)"
                    >
                        <RoomItem
                            :item="item"
                            :is-useing="usingRooms.includes(item.id!)"
                        />
                    </n-gi>
                </n-grid>
                <div v-if="loading" class="w-full flex-center py-10px">
                    加载中...
                </div>
                <div v-if="noMore" class="w-full flex-center py-10px">
                    没有更多了
                </div>
            </n-infinite-scroll>
        </div>
        <n-card
            class="w-25% h-full overflow-scroll"
            :style="
                !currentMeetingRoom ? 'opacity: 0; pointer-events: none;' : ''
            "
        >
            <n-divider>会议室信息</n-divider>
            <div class="overflow-scroll">
                <RoomDetail
                    v-if="currentMeetingRoom"
                    :room="currentMeetingRoom"
                />
            </div>
            <n-divider>近期预约</n-divider>
            <div
                v-if="currentRoomReservations.length === 0"
                class="w-full flex-center py-20px"
            >
                <n-empty description="暂无预约" />
            </div>
            <n-collapse
                v-else
                accordion
                class="mt-10px"
                default-expanded-names="1"
            >
                <template
                    v-for="(item, index) in currentRoomReservations"
                    :key="index"
                >
                    <n-collapse-item
                        :title="`编号-${item.reservationId}`"
                        :name="`${index + 1}`"
                    >
                        <n-list hoverable>
                            <n-list-item>
                                <n-thing
                                    title="预约日期"
                                    :title-extra="
                                        new Date(
                                            item.reserveDate
                                        ).toLocaleDateString()
                                    "
                                />
                            </n-list-item>
                            <n-list-item>
                                <n-thing
                                    title="预约时间"
                                    :title-extra="`${item.startTime}:00 - ${item.endTime}:00`"
                                />
                            </n-list-item>
                        </n-list>
                    </n-collapse-item>
                </template>
            </n-collapse>
        </n-card>
        <n-dropdown
            placement="bottom-start"
            trigger="manual"
            :x="xPos"
            :y="yPos"
            :options="dropdownOptions"
            :show="showDropdown"
            @clickoutside="showDropdown = false"
            @select="handleSelect"
        />
    </div>
</template>

<script lang="ts" setup>
import { h, ref, reactive, onMounted } from "vue";
import type { Component } from "vue";

import { NIcon } from "naive-ui";
import { Hammer, ReloadCircle, List, LockOpen } from "@vicons/ionicons5";

import type {
    MeetingRoom,
    MeetingRoomSearchParams,
    RoomReservations,
} from "@/service/api/types/room";

import {
    getRoomCounts,
    getRoomReservations,
    getMeetingRoomList,
    searchMeetingRooms,
    updateMeetingRoom,
    getUsingRooms,
} from "@/service/api/modules/room";
import { processRoomSearchParams } from "@/utils/room";

import RoomItem from "@/components/room-item/index.vue";
import RoomSearch from "@/views/admin/components/room-search/index.vue";
import RoomDetail from "@/views/admin/components/room-detail/index.vue";
import DynamicParam from "@/views/admin/components/dynamic-param/index.vue";

// 筛选会议室
const showPopover = ref(false);
const emptyParams: MeetingRoomSearchParams = {
    name: "",
    area: 0,
    capacity: 0,
    device: {
        speaker: false,
        projector: false,
        internet: false,
    },
    status: null,
    type: null,
};
const searchParams = ref<MeetingRoomSearchParams>(emptyParams);

// 会议室分页和加载
const loading = ref(false);
const noMore = ref(false);
const pagination = reactive({
    page: 1,
    size: 25,
    total: 0,
});

// 会议室数据
const meetingRooms = ref<MeetingRoom[]>([]);
const usingRooms = ref<string[]>([]); // 正在使用的会议室
const currentMeetingRoom = ref<MeetingRoom | null>();
const roomReservations: Map<string, RoomReservations[]> = new Map(); // 会议室的预约信息
const currentRoomReservations = ref<RoomReservations[]>([]); // 当前会议室的预约信息

// 右键菜单
const xPos = ref(0);
const yPos = ref(0);
const showDropdown = ref(false);

const renderIcon = (icon: Component) => {
    return () => {
        return h(
            NIcon,
            { size: 20 },
            {
                default: () => h(icon),
            }
        );
    };
};

const dropdownOptions = reactive([
    {
        label: "设置维修",
        key: "maintain",
        icon: renderIcon(Hammer),
        disabled: false,
    },
    {
        label: "维修结束",
        key: "unlock",
        icon: renderIcon(LockOpen),
        disabled: false,
    },
]);

// 加载更多会议室信息（也是分页获取，但是是滚动分批次）
const loadMeetingRooms = async () => {
    if (noMore.value) {
        return;
    }
    if (meetingRooms.value.length === pagination.total) {
        noMore.value = true;
        return;
    }
    loading.value = true;
    try {
        const res = await getMeetingRoomList({
            page: pagination.page++,
            size: pagination.size,
        });
        meetingRooms.value = meetingRooms.value.concat(res);
    } catch (err) {
        window.NMessage.error((err as Error).message);
    } finally {
        loading.value = false;
    }
};

onMounted(async () => {
    try {
        pagination.total = await getRoomCounts();
        if (pagination.total === 0) {
            noMore.value = true;
            return;
        }
        usingRooms.value = await getUsingRooms();
        loadMeetingRooms();
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
});

// 刷新界面
const handleRefresh = async () => {
    meetingRooms.value = [];
    roomReservations.clear();
    currentRoomReservations.value = [];
    searchParams.value = emptyParams;
    currentMeetingRoom.value = null;

    noMore.value = false;
    showPopover.value = false;

    try {
        pagination.total = await getRoomCounts();
        pagination.page = 1;
        loadMeetingRooms();
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

const handleClickRoomItem = async (room: MeetingRoom) => {
    currentMeetingRoom.value = room;
    if (roomReservations.has(room.id!)) {
        currentRoomReservations.value = roomReservations.get(room.id!)!;
        return;
    }
    // 获取该会议室现有的预约信息
    try {
        const reservations = await getRoomReservations(room.id!);
        roomReservations.set(room.id!, reservations);
        currentRoomReservations.value = reservations;
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

// 筛选会议室事件
const handleSearchRooms = async (params: MeetingRoomSearchParams) => {
    searchParams.value = params;
    showPopover.value = false;
    currentMeetingRoom.value = null;
    try {
        const params_ = processRoomSearchParams(params);
        if (Object.keys(params_).length === 0) {
            noMore.value = false;
            meetingRooms.value = [];
            loadMeetingRooms();
            return;
        }
        pagination.page = 1;
        noMore.value = true;
        meetingRooms.value = await searchMeetingRooms(params_);
    } catch (err) {
        window.NMessage.error((err as Error).message);
    }
};

// 显示右键菜单
const handleContextMenu = (e: MouseEvent, item: MeetingRoom) => {
    e.preventDefault();
    xPos.value = e.clientX;
    yPos.value = e.clientY;
    currentMeetingRoom.value = item;
    showDropdown.value = true;

    dropdownOptions[0].disabled = item.maintained!;
    dropdownOptions[1].disabled = !item.maintained!;
};

// 点击右键菜单，设置会议室维修状态或维修结束
const handleSelect = (key: string) => {
    const dialogParams = (
        title: string,
        content: string,
        callback: () => void
    ) => {
        return {
            title,
            content,
            positiveText: "确定",
            negativeText: "取消",
            onPositiveClick: async () => {
                callback();
            },
        };
    };

    showDropdown.value = false;
    if (key === "maintain") {
        if (usingRooms.value.includes(currentMeetingRoom.value!.id!)) {
            window.NMessage.error("该会议室正在使用中");
            return;
        }
        window.NDialog.warning(
            dialogParams("设置维修", "是否确定该会议室需要维修？", async () => {
                try {
                    currentMeetingRoom.value!.maintained = true;
                    await updateMeetingRoom(currentMeetingRoom.value!);
                    handleRefresh();
                    window.NMessage.success("设置成功");
                } catch (err) {
                    window.NMessage.error((err as Error).message);
                }
            })
        );
    } else {
        window.NDialog.warning(
            dialogParams("维修结束", "是否确定维修结束？", async () => {
                try {
                    currentMeetingRoom.value!.maintained = false;
                    await updateMeetingRoom(currentMeetingRoom.value!);
                    handleRefresh();
                    window.NMessage.success("设置成功");
                } catch (err) {
                    window.NMessage.error((err as Error).message);
                }
            })
        );
    }
};
</script>

<style scoped>
:deep(.n-divider) {
    margin: 4px;
}
</style>
